% METODO DELLE SUCCESSIVE BISEZIONI 
% PER LA SOLUZIONE DI EQUAZIONI NON LINEARI
%
% function [x,fx,exitflag,output] = bzero(fun,dfun,x0,options)
%
% DATI DI INPUT:
%   fun = stringa contenente il nome della funzione
%  dfun = stringa contenente il nome della deribvata prima della funzione
%   x0  = approssimazione iniziale dello zero  
%   options = struttura contenente dati opzionali 
%     options.TolX     = tolleranza
%     options.Nmax    = numero massimo di iterate
%     options.Display = livello di visualizzazione 
%                'off'    nessuna visualizzazione;
%                'iter'   visualizzazione per ogni iterata; 
%                'final'  visualizzazione finale;
%                'notify' (default) visualizzazione solo se il metodo non converge.
% DATI DI OUTPUT:
%    x   = soluzione
%    fx  = valore della funzione in x
%    exitflag = flag di errore 
%         exitflag = 1  nessun errore
%         exitflag = -1  numero di iterate maggiore di nmax
%        
%    output = struttura
%       output.algorithm = algoritmo usato
%        output.funcCount  = valutazioni di funzioni
%        output.iterations = numero di iterazioni
%
function [x,fx,exitflag,output] = bzero(fun,dfun,x0,options)

   
output.algorithm = 'newton';
fx0 = feval(fun,x0);
x = x0;
fx = fx0;
if abs(fx0) == 0
   exitflag =1;
   output.funcCount   = 1;
   output.iterations= 0;
    return
end
if nargin == 3
    tol  = eps; 
    nmax = 100;
    displaynot = 1;
    displayit  =0;
    displayfin =0;
else
    if isfield(options,'TolX')
        if ~isempty(options.TolX)
            tol=options.TolX;
        else
            tol=eps;
        end
    else
        tol = eps;
    end
    if isfield(options,'Nmax')
        if ~isempty(options.Nmax)
            nmax = options.Nmax;
        else
            nmax=100;
        end
    else
        nmax=100;
    end
    if isfield(options,'Display')
        if ~isempty(options.Display)
            display = lower(options.Display);
            switch display
            case {'off'}
                displaynot =0;
                displayit  =0;
                displayfin =0;   
            case{'final'}
                displaynot =0;
                displayit  =0;
                displayfin =1;
            case{'iter'}
                displaynot =0;
                displayit  =1;
                displayfin =0;
            case{'notify'}
                displaynot =1;
                displayit  =0;
                displayfin =0;
            end
        else
            displaynot =1;
            displayit  =0;
            displayfin =0;
        end
    else
        displaynot =1;
        displayit  =0;
        displayfin =0;
    end
end


vai_crit = 1;
nit = 1;
fcont=1;
if displayit
    fprintf('Val. funzioni Iterationi            x           f(x)\n')
end

while vai_crit & (nit <= nmax)
    x0 = x;
    fx0 = fx;
    dfx0 = feval(dfun,x0);
    fcont = fcont+1;
    x = x0 - fx0/dfx0;
    fx = feval(fun,x);
    fcont = fcont+1;
    if displayit
       fprintf('%10.0f %10.0f   %13.6g %13.6g    \n',fcont, nit,x,fx')
    end
    if abs(fx) == 0
       
       exitflag =1;
       output.funcCount   = fcont;
       output.iterations= nit;
       return
    end
    nit = nit+1;
    vai_crit = abs(x0-x)/max(1,min(abs(x0),abs(x))) > tol;

end


if nit > nmax | isnan(x) | isinf(x) | isnan(fx) | isinf(fx)
 
    exitflag =-1;
   output.funcCount   = fcont;
   output.iterations= nit-1;    
   if displaynot 
       if nit > nmax
        fprintf(' Numero massimo di iterate raggiunto \n')
    else
         fprintf(' Inf o NaN')
    end
    
        fprintf('Val. funzioni Iterationi            x           f(x)\n') 
        fprintf('%10.0f %10.0f   %13.6g %13.6g    \n',fcont, nit,x,fx')   
    end
else
   
   exitflag =1;
   output.funcCount   = fcont;
   output.iterations= nit-1;
   if displayfin
      fprintf('Soluzione trovata nell''intervallo [%13.6g %13.6g]',a,b)
       fprintf('Val. funzioni Iterationi            x           f(x)\n')
      fprintf('%10.0f %10.0f   %13.6g %13.6g    \n',fcont, nit,x,fx')
    end
   
end